<template><div><h2 id="模块" tabindex="-1"><a class="header-anchor" href="#模块"><span>模块</span></a></h2>
<p>模块是一个独立的软件单元，由 <a href="https://github.com/yiisoft/yii2/blob/master/docs/guide-zh-CN/structure-models.md" target="_blank" rel="noopener noreferrer">模型</a>、<a href="https://github.com/yiisoft/yii2/blob/master/docs/guide-zh-CN/structure-views.md" target="_blank" rel="noopener noreferrer">视图</a>、<a href="https://github.com/yiisoft/yii2/blob/master/docs/guide-zh-CN/structure-controllers.md" target="_blank" rel="noopener noreferrer">控制器</a> 和其他支持组件组成，终端用户可以访问在 <a href="https://github.com/yiisoft/yii2/blob/master/docs/guide-zh-CN/structure-applications.md" target="_blank" rel="noopener noreferrer">应用主体</a> 中已安装的模块的控制器，模块被当成小应用主体来看待，不同的是，模块不能单独部署，必须属于某个应用主体。</p>
<h2 id="创建模块" tabindex="-1"><a class="header-anchor" href="#创建模块"><span>创建模块</span></a></h2>
<p>模块被组织成一个称为 [[yii\base\Module::basePath]] 的目录里，在其中有 <code v-pre>controllers</code>，<code v-pre>models</code>，<code v-pre>views</code> 等子目录，分别为对应控制器，模型，视图及其他代码，和应用非常类似。一个模型的目录结构，如下所示：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line">forum<span class="token operator">/</span></span>
<span class="line">    Module<span class="token operator">.</span>php                   模块类文件</span>
<span class="line">    controllers<span class="token operator">/</span>                 包含控制器类文件</span>
<span class="line">        DefaultController<span class="token operator">.</span>php    <span class="token keyword">default</span> 控制器类文件</span>
<span class="line">    models<span class="token operator">/</span>                      包含模型类文件</span>
<span class="line">    views<span class="token operator">/</span>                       包含控制器视图文件和布局文件</span>
<span class="line">        layouts<span class="token operator">/</span>                 包含布局文件</span>
<span class="line">        <span class="token keyword">default</span><span class="token operator">/</span>                 包含 DefaultController 控制器视图文件</span>
<span class="line">            index<span class="token operator">.</span>php            index 视图文件</span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><h3 id="模块类" tabindex="-1"><a class="header-anchor" href="#模块类"><span>模块类</span></a></h3>
<p>每个模块都有一个继承 <code v-pre>yii\base\Module</code> 的模块类文件 <code v-pre>Module.php</code>，它放在该模块的根目录下，并且能被 <a href="https://github.com/yiisoft/yii2/blob/master/docs/guide-zh-CN/concept-autoloading.md" target="_blank" rel="noopener noreferrer">自动加载</a>。当一个模块被访问，和 <a href="https://github.com/yiisoft/yii2/blob/master/docs/guide-zh-CN/structure-applications.md" target="_blank" rel="noopener noreferrer">应用主体实例</a> 类似，会创建该模块类唯一实例，模块实例用来帮模块内代码共享数据和组件。一个模块类大致定义如下：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token keyword">namespace</span> <span class="token package">app<span class="token punctuation">\</span>modules<span class="token punctuation">\</span>forum</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token keyword">class</span> <span class="token class-name-definition class-name">Module</span> <span class="token keyword">extends</span> <span class="token class-name class-name-fully-qualified"><span class="token punctuation">\</span>yii<span class="token punctuation">\</span>base<span class="token punctuation">\</span>Module</span></span>
<span class="line"><span class="token punctuation">{</span></span>
<span class="line">    <span class="token keyword">public</span> <span class="token keyword">function</span> <span class="token function-definition function">init</span><span class="token punctuation">(</span><span class="token punctuation">)</span></span>
<span class="line">    <span class="token punctuation">{</span></span>
<span class="line">        <span class="token keyword static-context">parent</span><span class="token operator">::</span><span class="token function">init</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line">        <span class="token variable">$this</span><span class="token operator">-></span><span class="token property">params</span><span class="token punctuation">[</span><span class="token string single-quoted-string">'foo'</span><span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token string single-quoted-string">'bar'</span><span class="token punctuation">;</span></span>
<span class="line">        <span class="token comment">// ...  其他初始化代码 ...</span></span>
<span class="line">    <span class="token punctuation">}</span></span>
<span class="line"><span class="token punctuation">}</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>如果 <code v-pre>init()</code> 方法包含很多初始化模块属性代码， 可将他们保存在 <a href="https://github.com/yiisoft/yii2/blob/master/docs/guide-zh-CN/concept-configurations.md" target="_blank" rel="noopener noreferrer">配置</a> 并在 <code v-pre>init()</code> 中使用以下代码加载：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token keyword">public</span> <span class="token keyword">function</span> <span class="token function-definition function">init</span><span class="token punctuation">(</span><span class="token punctuation">)</span></span>
<span class="line"><span class="token punctuation">{</span></span>
<span class="line">    <span class="token keyword static-context">parent</span><span class="token operator">::</span><span class="token function">init</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line">    <span class="token comment">// 从config.php 加载配置来初始化模块</span></span>
<span class="line">    <span class="token class-name class-name-fully-qualified static-context"><span class="token punctuation">\</span>Yii</span><span class="token operator">::</span><span class="token function">configure</span><span class="token punctuation">(</span><span class="token variable">$this</span><span class="token punctuation">,</span> <span class="token keyword">require</span> <span class="token constant">__DIR__</span> <span class="token operator">.</span> <span class="token string single-quoted-string">'/config.php'</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token punctuation">}</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p><code v-pre>config.php</code> 配置文件可能包含以下内容，类似 <a href="https://github.com/yiisoft/yii2/blob/master/docs/guide-zh-CN/structure-applications.md#application-configurations" target="_blank" rel="noopener noreferrer">应用主体配置</a>。</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token php language-php"><span class="token delimiter important">&lt;?php</span></span>
<span class="line"><span class="token keyword">return</span> <span class="token punctuation">[</span></span>
<span class="line">    <span class="token string single-quoted-string">'components'</span> <span class="token operator">=></span> <span class="token punctuation">[</span></span>
<span class="line">        <span class="token comment">// list of component configurations</span></span>
<span class="line">    <span class="token punctuation">]</span><span class="token punctuation">,</span></span>
<span class="line">    <span class="token string single-quoted-string">'params'</span> <span class="token operator">=></span> <span class="token punctuation">[</span></span>
<span class="line">        <span class="token comment">// list of parameters</span></span>
<span class="line">    <span class="token punctuation">]</span><span class="token punctuation">,</span></span>
<span class="line"><span class="token punctuation">]</span><span class="token punctuation">;</span></span>
<span class="line"></span></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><h3 id="模块中的控制器" tabindex="-1"><a class="header-anchor" href="#模块中的控制器"><span>模块中的控制器</span></a></h3>
<p>创建模块的控制器时，惯例是将控制器类放在模块类命名空间的 <code v-pre>controllers</code> 子命名空间中，也意味着要将控制器类文件放在模块根目录下的 <code v-pre>controllers</code> 子目录中。例如，上小节中要在 <code v-pre>forum</code> 模块中创建 <code v-pre>post</code> 控制器，应像如下申明控制器类：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token keyword">namespace</span> <span class="token package">app<span class="token punctuation">\</span>modules<span class="token punctuation">\</span>forum<span class="token punctuation">\</span>controllers</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token keyword">use</span> <span class="token package">yii<span class="token punctuation">\</span>web<span class="token punctuation">\</span>Controller</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token keyword">class</span> <span class="token class-name-definition class-name">PostController</span> <span class="token keyword">extends</span> <span class="token class-name">Controller</span></span>
<span class="line"><span class="token punctuation">{</span></span>
<span class="line">    <span class="token comment">// ...</span></span>
<span class="line"><span class="token punctuation">}</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>可配置 [[yii\base\Module::controllerNamespace]] 属性来自定义控制器类的命名空间，如果一些控制器不在该命名空间下，可配置 [[yii\base\Module::controllerMap]] 属性，让它们能被访问， 这类似于 <a href="https://github.com/yiisoft/yii2/blob/master/docs/guide-zh-CN/structure-applications.md#controller-map" target="_blank" rel="noopener noreferrer">应用主体配置</a> 所做的。</p>
<h3 id="模块中的视图" tabindex="-1"><a class="header-anchor" href="#模块中的视图"><span>模块中的视图</span></a></h3>
<p>视图应放在模块的根目录下的 <code v-pre>views</code> 目录中，对于模块中控制器对应的视图文件应放在 <code v-pre>views/ControllerID</code> 目录下，其中 <code v-pre>ControllerID</code> 对应 <a href="https://github.com/yiisoft/yii2/blob/master/docs/guide-zh-CN/structure-controllers.md#routes" target="_blank" rel="noopener noreferrer">控制器 ID</a>。例如，假定控制器类为 <code v-pre>PostController</code>，视图的目录对应模块根目录下的 <code v-pre>views/post</code> 目录。</p>
<p>模块可指定 <a href="https://github.com/yiisoft/yii2/blob/master/docs/guide-zh-CN/structure-views.md#layouts" target="_blank" rel="noopener noreferrer">布局</a>，它用在模块的控制器视图渲染。布局文件默认放在 <code v-pre>views/layouts</code> 目录下，可配置 [[yii\base\Module::layout]] 属性指定布局名，如果没有配置 <code v-pre>layout</code> 属性名，默认会使用应用的布局。</p>
<h3 id="模块中的控制台命令" tabindex="-1"><a class="header-anchor" href="#模块中的控制台命令"><span>模块中的控制台命令</span></a></h3>
<p>模块中也可以声明命令，这将通过 <a href="https://github.com/yiisoft/yii2/blob/master/docs/guide-zh-CN/tutorial-console.md" target="_blank" rel="noopener noreferrer">控制台</a> 模式可用。</p>
<p>当 Yii 在控制台模式下执行并将其指向命令的命名空间时。想要在命令行中查看你的命令，你需要更改 [[yii\base\Module::controllerNamespace]] 属性。</p>
<p>一种实现方法是在模块的 <code v-pre>init()</code> 方法中测试Yii应用程序的实例类型：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token keyword">public</span> <span class="token keyword">function</span> <span class="token function-definition function">init</span><span class="token punctuation">(</span><span class="token punctuation">)</span></span>
<span class="line"><span class="token punctuation">{</span></span>
<span class="line">    <span class="token keyword static-context">parent</span><span class="token operator">::</span><span class="token function">init</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line">    <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token class-name static-context">Yii</span><span class="token operator">::</span><span class="token variable">$app</span> <span class="token keyword">instanceof</span> <span class="token class-name class-name-fully-qualified"><span class="token punctuation">\</span>yii<span class="token punctuation">\</span>console<span class="token punctuation">\</span>Application</span><span class="token punctuation">)</span> <span class="token punctuation">{</span></span>
<span class="line">        <span class="token variable">$this</span><span class="token operator">-></span><span class="token property">controllerNamespace</span> <span class="token operator">=</span> <span class="token string single-quoted-string">'app\modules\forum\commands'</span><span class="token punctuation">;</span></span>
<span class="line">    <span class="token punctuation">}</span></span>
<span class="line"><span class="token punctuation">}</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>然后您的命令将从命令行使用以下路由：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line">yii <span class="token operator">&lt;</span>module_id<span class="token operator">></span><span class="token operator">/</span><span class="token operator">&lt;</span>command<span class="token operator">></span><span class="token operator">/</span><span class="token operator">&lt;</span>sub_command<span class="token operator">></span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div></div></div><h2 id="使用模块" tabindex="-1"><a class="header-anchor" href="#使用模块"><span>使用模块</span></a></h2>
<p>要在应用中使用模块，只需要将模块加入到应用主体配置的[[yii\base\Application::modules|modules]] 属性的列表中，如下代码的 <a href="https://github.com/yiisoft/yii2/blob/master/docs/guide-zh-CN/structure-applications.md#application-configurations" target="_blank" rel="noopener noreferrer">应用主体配置</a> 使用 <code v-pre>forum</code> 模块：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token punctuation">[</span></span>
<span class="line">    <span class="token string single-quoted-string">'modules'</span> <span class="token operator">=></span> <span class="token punctuation">[</span></span>
<span class="line">        <span class="token string single-quoted-string">'forum'</span> <span class="token operator">=></span> <span class="token punctuation">[</span></span>
<span class="line">            <span class="token string single-quoted-string">'class'</span> <span class="token operator">=></span> <span class="token string single-quoted-string">'app\modules\forum\Module'</span><span class="token punctuation">,</span></span>
<span class="line">            <span class="token comment">// ... 模块其他配置 ...</span></span>
<span class="line">        <span class="token punctuation">]</span><span class="token punctuation">,</span></span>
<span class="line">    <span class="token punctuation">]</span><span class="token punctuation">,</span></span>
<span class="line"><span class="token punctuation">]</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>[[yii\base\Application::modules|modules]] 属性使用模块配置数组，每个数组键为<em>模块 ID</em>，它标识该应用中唯一的模块，数组的值为用来创建模块的 <a href="https://github.com/yiisoft/yii2/blob/master/docs/guide-zh-CN/concept-configurations.md" target="_blank" rel="noopener noreferrer">配置</a>。</p>
<h3 id="路由" tabindex="-1"><a class="header-anchor" href="#路由"><span>路由</span></a></h3>
<p>和访问应用的控制器类似，<a href="https://github.com/yiisoft/yii2/blob/master/docs/guide-zh-CN/structure-controllers.md#routes" target="_blank" rel="noopener noreferrer">路由</a> 也用在模块中控制器的寻址，模块中控制器的路由必须以模块 ID 开始，接下来为控制器 ID 和操作 ID。例如，假定应用使用一个名为 <code v-pre>forum</code> 模块，路由<code v-pre>forum/post/index</code> 代表模块中 <code v-pre>post</code> 控制器的 <code v-pre>index</code> 操作，如果路由只包含模块ID，默认为 <code v-pre>default</code> 的 [[yii\base\Module::defaultRoute]] 属性来决定使用哪个控制器/操作， 也就是说路由 <code v-pre>forum</code> 可能代表 <code v-pre>forum</code> 模块的 <code v-pre>default</code> 控制器。</p>
<p>在 [[yii\web\UrlManager::parseRequest()]] 被触发之前应该添加模块 URL 管理器规则。 这就意味着在模块的 <code v-pre>init()</code> 将不会起作用，因为模块将在路由开始处理时被初始化。 因此应该在 <a href="https://github.com/yiisoft/yii2/blob/master/docs/guide-zh-CN/structure-extensions.md#bootstrapping-classes" target="_blank" rel="noopener noreferrer">bootstrap stage</a> 添加规则。使用 [[\yii\web\GroupUrlRule]] 去实现模块的 URL 规则也是一种很好的做法。</p>
<p>如果一个模块用于 <a href="https://github.com/yiisoft/yii2/blob/master/docs/guide-zh-CN/rest-versioning.md" target="_blank" rel="noopener noreferrer">version API</a>，它的 URL 规则应该直接添加到应用程序配置的 <code v-pre>urlManager</code> 中。</p>
<h3 id="访问模块" tabindex="-1"><a class="header-anchor" href="#访问模块"><span>访问模块</span></a></h3>
<p>在模块中，可能经常需要获取<a href="https://github.com/yiisoft/yii2/blob/master/docs/guide-zh-CN/structure-modules.md#module-classes" target="_blank" rel="noopener noreferrer">模块类</a>的实例来访问模块ID，模块参数，模块组件等，可以使用如下语句来获取：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token variable">$module</span> <span class="token operator">=</span> <span class="token class-name static-context">MyModuleClass</span><span class="token operator">::</span><span class="token function">getInstance</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div></div></div><p>其中 <code v-pre>MyModuleClass</code> 对应你想要的模块类，<code v-pre>getInstance()</code> 方法返回当前请求的模块类实例，如果模块没有被请求，该方法会返回空，注意不需要手动创建一个模块类，因为手动创建的和Yii处理请求时自动创建的不同。</p>
<blockquote>
<p>Info: 当开发模块时，你不能假定模块使用固定的 ID，因为在应用或其他没模块中，模块可能会对应到任意的 ID，为了获取模块 ID，应使用上述代码获取模块实例，然后通过 <code v-pre>$module-&gt;id</code> 获取模块 ID。</p>
</blockquote>
<p>也可以使用如下方式访问模块实例:</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token comment">// 获取ID为 "forum" 的模块</span></span>
<span class="line"><span class="token variable">$module</span> <span class="token operator">=</span> <span class="token class-name class-name-fully-qualified static-context"><span class="token punctuation">\</span>Yii</span><span class="token operator">::</span><span class="token variable">$app</span><span class="token operator">-></span><span class="token function">getModule</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'forum'</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token comment">// 获取处理当前请求控制器所属的模块</span></span>
<span class="line"><span class="token variable">$module</span> <span class="token operator">=</span> <span class="token class-name class-name-fully-qualified static-context"><span class="token punctuation">\</span>Yii</span><span class="token operator">::</span><span class="token variable">$app</span><span class="token operator">-></span><span class="token property">controller</span><span class="token operator">-></span><span class="token property">module</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>第一种方式仅在你知道模块 ID 的情况下有效，第二种方式在你知道处理请求的控制器下使用。</p>
<p>一旦获取到模块实例，可访问注册到模块的参数和组件，例如：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token variable">$maxPostCount</span> <span class="token operator">=</span> <span class="token variable">$module</span><span class="token operator">-></span><span class="token property">params</span><span class="token punctuation">[</span><span class="token string single-quoted-string">'maxPostCount'</span><span class="token punctuation">]</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div></div></div><h3 id="引导启动模块" tabindex="-1"><a class="header-anchor" href="#引导启动模块"><span>引导启动模块</span></a></h3>
<p>有些模块在每个请求下都有运行，[[yii\debug\Module|debug]] 模块就是这种，为此将这种模块加入到应用主体的 [[yii\base\Application::bootstrap|bootstrap]] 属性中。</p>
<p>例如，如下示例的应用主体配置会确保 <code v-pre>debug</code> 模块每次都被加载：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token punctuation">[</span></span>
<span class="line">    <span class="token string single-quoted-string">'bootstrap'</span> <span class="token operator">=></span> <span class="token punctuation">[</span></span>
<span class="line">        <span class="token string single-quoted-string">'debug'</span><span class="token punctuation">,</span></span>
<span class="line">    <span class="token punctuation">]</span><span class="token punctuation">,</span></span>
<span class="line"></span>
<span class="line">    <span class="token string single-quoted-string">'modules'</span> <span class="token operator">=></span> <span class="token punctuation">[</span></span>
<span class="line">        <span class="token string single-quoted-string">'debug'</span> <span class="token operator">=></span> <span class="token string single-quoted-string">'yii\debug\Module'</span><span class="token punctuation">,</span></span>
<span class="line">    <span class="token punctuation">]</span><span class="token punctuation">,</span></span>
<span class="line"><span class="token punctuation">]</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><h2 id="模块嵌套" tabindex="-1"><a class="header-anchor" href="#模块嵌套"><span>模块嵌套</span></a></h2>
<p>模块可无限级嵌套，也就是说，模块可以包含另一个包含模块的模块，我们称前者为<em>父模块</em>，后者为<em>子模块</em>，子模块必须在父模块的 [[yii\base\Module::modules|modules]] 属性中申明，例如：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token keyword">namespace</span> <span class="token package">app<span class="token punctuation">\</span>modules<span class="token punctuation">\</span>forum</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token keyword">class</span> <span class="token class-name-definition class-name">Module</span> <span class="token keyword">extends</span> <span class="token class-name class-name-fully-qualified"><span class="token punctuation">\</span>yii<span class="token punctuation">\</span>base<span class="token punctuation">\</span>Module</span></span>
<span class="line"><span class="token punctuation">{</span></span>
<span class="line">    <span class="token keyword">public</span> <span class="token keyword">function</span> <span class="token function-definition function">init</span><span class="token punctuation">(</span><span class="token punctuation">)</span></span>
<span class="line">    <span class="token punctuation">{</span></span>
<span class="line">        <span class="token keyword static-context">parent</span><span class="token operator">::</span><span class="token function">init</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line">        <span class="token variable">$this</span><span class="token operator">-></span><span class="token property">modules</span> <span class="token operator">=</span> <span class="token punctuation">[</span></span>
<span class="line">            <span class="token string single-quoted-string">'admin'</span> <span class="token operator">=></span> <span class="token punctuation">[</span></span>
<span class="line">                <span class="token comment">// 此处应考虑使用一个更短的命名空间</span></span>
<span class="line">                <span class="token string single-quoted-string">'class'</span> <span class="token operator">=></span> <span class="token string single-quoted-string">'app\modules\forum\modules\admin\Module'</span><span class="token punctuation">,</span></span>
<span class="line">            <span class="token punctuation">]</span><span class="token punctuation">,</span></span>
<span class="line">        <span class="token punctuation">]</span><span class="token punctuation">;</span></span>
<span class="line">    <span class="token punctuation">}</span></span>
<span class="line"><span class="token punctuation">}</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>在嵌套模块中的控制器，它的路由应包含它所有祖先模块的ID，例如<code v-pre>forum/admin/dashboard/index</code> 代表 在模块 <code v-pre>forum</code> 中子模块 <code v-pre>admin</code> 中 <code v-pre>dashboard</code> 控制器的 <code v-pre>index</code> 操作。</p>
<blockquote>
<p>Info: [[yii\base\Module::getModule()|getModule()]] 方法只返回子模块的直属的父模块。[[yii\base\Application::loadedModules]] 保存了已加所有载模块的属性，包括两者的子模块和嵌套模块，并用他们的类名进行索引。</p>
</blockquote>
<h2 id="从模块内部访问组件" tabindex="-1"><a class="header-anchor" href="#从模块内部访问组件"><span>从模块内部访问组件</span></a></h2>
<p>从 2.0.13 版本开始模块支持 <a href="https://github.com/yiisoft/yii2/blob/master/docs/guide-zh-CN/concept-service-locator.md#tree-traversal" target="_blank" rel="noopener noreferrer">树遍历</a>。 这允发模块开发人员通过作为其模块的服务定位器去引用（应用程序）组件。这意味着最好使用 <code v-pre>$module-&gt;get('db')</code> 而不是 <code v-pre>Yii::$app-&gt;get('db')</code>。在需要不同组件（配置）的情况下，模块开发者能够指定要用于模块的特定组件。</p>
<p>例如，以下是部分应用程序的配置：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token string single-quoted-string">'components'</span> <span class="token operator">=></span> <span class="token punctuation">[</span></span>
<span class="line">    <span class="token string single-quoted-string">'db'</span> <span class="token operator">=></span> <span class="token punctuation">[</span></span>
<span class="line">        <span class="token string single-quoted-string">'tablePrefix'</span> <span class="token operator">=></span> <span class="token string single-quoted-string">'main_'</span><span class="token punctuation">,</span></span>
<span class="line">        <span class="token string single-quoted-string">'class'</span> <span class="token operator">=></span> <span class="token class-name static-context">Connection</span><span class="token operator">::</span><span class="token keyword">class</span><span class="token punctuation">,</span></span>
<span class="line">        <span class="token string single-quoted-string">'enableQueryCache'</span> <span class="token operator">=></span> <span class="token constant boolean">false</span></span>
<span class="line">    <span class="token punctuation">]</span><span class="token punctuation">,</span></span>
<span class="line"><span class="token punctuation">]</span><span class="token punctuation">,</span></span>
<span class="line"><span class="token string single-quoted-string">'modules'</span> <span class="token operator">=></span> <span class="token punctuation">[</span></span>
<span class="line">    <span class="token string single-quoted-string">'mymodule'</span> <span class="token operator">=></span> <span class="token punctuation">[</span></span>
<span class="line">        <span class="token string single-quoted-string">'components'</span> <span class="token operator">=></span> <span class="token punctuation">[</span></span>
<span class="line">            <span class="token string single-quoted-string">'db'</span> <span class="token operator">=></span> <span class="token punctuation">[</span></span>
<span class="line">                <span class="token string single-quoted-string">'tablePrefix'</span> <span class="token operator">=></span> <span class="token string single-quoted-string">'module_'</span><span class="token punctuation">,</span></span>
<span class="line">                <span class="token string single-quoted-string">'class'</span> <span class="token operator">=></span> <span class="token class-name static-context">Connection</span><span class="token operator">::</span><span class="token keyword">class</span></span>
<span class="line">            <span class="token punctuation">]</span><span class="token punctuation">,</span></span>
<span class="line">        <span class="token punctuation">]</span><span class="token punctuation">,</span></span>
<span class="line">    <span class="token punctuation">]</span><span class="token punctuation">,</span></span>
<span class="line"><span class="token punctuation">]</span><span class="token punctuation">,</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>应用程序数据表将会以 <code v-pre>main_</code> 作为前缀，而所有模块表都将以 <code v-pre>module_</code> 为前缀。注意上面的配置并未合并；例如模块的组件都将启用查询缓存，因为这是默认的设置。</p>
<h2 id="最佳实践" tabindex="-1"><a class="header-anchor" href="#最佳实践"><span>最佳实践</span></a></h2>
<p>模块在大型项目中常备使用，这些项目的特性可分组，每个组包含一些强相关的特性，每个特性组可以做成一个模块由特定的开发人员和开发组来开发和维护。</p>
<p>在特性组上，使用模块也是重用代码的好方式，一些常用特性，如用户管理，评论管理，可以开发成模块，这样在相关项目中非常容易被重用。</p>
<blockquote>
<p>💖喜欢本文档的，欢迎点赞、收藏、留言或转发，谢谢支持！<br>
作者邮箱：zhuzixian520@126.com，github地址：<a href="https://github.com/zhuzixian520" target="_blank" rel="noopener noreferrer">github.com/zhuzixian520</a></p>
</blockquote>
</div></template>


